package cn.cxyxj.code_auth_jwt_persistence_prod.auth.handler;

import cn.cxyxj.code_auth_jwt_persistence_prod.common.ApiResult;
import cn.cxyxj.code_auth_jwt_persistence_prod.common.ApiResultEnum;
import cn.cxyxj.code_auth_jwt_persistence_prod.common.RedisKey;
import cn.cxyxj.code_auth_jwt_persistence_prod.entity.OauthClientDetails;
import cn.cxyxj.code_auth_jwt_persistence_prod.entity.SysUser;
import cn.cxyxj.code_auth_jwt_persistence_prod.entity.SysUserDetails;
import cn.cxyxj.code_auth_jwt_persistence_prod.service.IOauthClientDetailsService;
import cn.cxyxj.code_auth_jwt_persistence_prod.utils.RedisUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 注销成功回调
 *
 * @author cxyxj
 */
@Slf4j
@Component
public class CustomizeLogoutSuccessHandler implements LogoutHandler {

    @Autowired
    private IOauthClientDetailsService oauthClientDetailsService;

    private final static String LOGOUT_NOTIFY_URL_KEY = "LOGOUT_NOTIFY_URL";


    @Resource
    private TaskExecutor taskExecutor;

    @Resource
    private RestTemplate restTemplate;

    @SneakyThrows
    @Override
    public void logout(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) {
        System.out.println("=======onLogoutSuccess===============");
        Cookie[] cookies = req.getCookies();
        String token = "";
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(RedisKey.SSO_USER_TOKEN)) {
                    token = cookie.getValue();
                }
            }
        }
        if (StringUtils.isBlank(token)) {
            log.info("token is blank");
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("application/json;charset=UTF-8");
            resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            resp.getWriter().write(JSONObject.toJSONString(ApiResult.fail(ApiResultEnum.UNAUTHORIZED_ERROR)));
            return;
        }
        // 根据统一认证中心用户 token 查询所有颁发的access_token
        SysUserDetails sysUserDetails = RedisUtil.get(String.format(RedisKey.TOKEN, token), SysUserDetails.class);
        if (Objects.isNull(sysUserDetails)) {
            log.info("token is error");
            resp.setCharacterEncoding("UTF-8");
            resp.setContentType("application/json;charset=UTF-8");
            resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            resp.getWriter().write(JSONObject.toJSONString(ApiResult.fail(ApiResultEnum.UNAUTHORIZED_ERROR)));
            return;
        }
        SysUser sysUser = sysUserDetails.getSysUser();
        List<Object> clients = RedisUtil.lGet(String.format(RedisKey.USER_CLIENT, sysUser.getAccount()));
        List<String> strs = clients.stream().map(obj -> (String) obj).collect(Collectors.toList());

        // 根据 clients 查询客户端退出回调地址
        List<OauthClientDetails> oauthClientDetails = oauthClientDetailsService.queryClientIds(strs);
        for (OauthClientDetails client : oauthClientDetails) {
            String additionalInformation = client.getAdditionalInformation();
            String clientId = client.getClientId();
            HashMap informationMap = JSONObject.parseObject(additionalInformation, HashMap.class);

            Object accessToken = RedisUtil.get(String.format(RedisKey.CLIENT_ACCESS_TOKEN, sysUser.getAccount(), clientId));
            String url = (String) informationMap.get(LOGOUT_NOTIFY_URL_KEY);
            HashMap<String, Object> paramMap = new HashMap<>(2);
            paramMap.put("account", sysUser.getAccount());
            paramMap.put("accessToken", accessToken);
            String paramUrl = URLUtil.buildQuery(paramMap, null);
            String finalUrl = url +"?"+ paramUrl;
            taskExecutor.execute(() -> {
                try {
                    restTemplate.getForObject(finalUrl, Void.class);
                } catch (Exception e) {
                    log.warn(e.getMessage());
                }
            });

            RedisUtil.del(String.format(RedisKey.RESOURCES_ACCESS_TOKEN, accessToken));
            RedisUtil.del(String.format(RedisKey.CLIENT_ACCESS_TOKEN, sysUser.getAccount(), clientId));
            RedisUtil.del(String.format(RedisKey.CLIENT_REFRESH_TOKEN, sysUser.getAccount(), clientId));
        }

        RedisUtil.del(String.format(RedisKey.USER_CLIENT,sysUser.getAccount()));
        RedisUtil.del(String.format(RedisKey.TOKEN , token));
        RedisUtil.del(String.format(RedisKey.USER_TOKEN , sysUser.getAccount()));

    }

}
